package main

import (
	"context"
	"fmt"
	"os"
	"time"

	"v8s-controller/generator"
	"v8s-controller/internal/configuration"
	"v8s-controller/internal/controller"
	"v8s-controller/internal/db"
	"v8s-controller/internal/handlers"
	"v8s-controller/internal/k8s"
	"v8s-controller/internal/logging"
	"v8s-controller/rest/target/generated-sources"
	server "v8s/http-server"
	"v8s/logger"

	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

func main() {
	properties := configuration.ReadProperties()
	logger.BuildLogger(properties.Log)

	timeout, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
	mongoClient := db.CreateMongoClient(timeout, properties.Mongo)
	cancel()

	databaseRepository := db.CreateProjectsRepository(mongoClient, properties.Mongo)

	k8sClient := getK8SClient()
	k8sRepository := k8s.CreateRepository(k8sClient)

	gen := generator.NewGenerator(properties.Generator)

	synchronizationController := controller.CreateSynchronizationController(databaseRepository, k8sRepository, gen, *properties)
	synchronizationScheduler := controller.NewScheduler(synchronizationController, properties.SynchronizationController)
	go synchronizationScheduler.Run()

	metricsScheduler := controller.NewScheduler(controller.NewTaskMetricsController(databaseRepository), properties.TaskMetricsController)
	go metricsScheduler.Run()

	if properties.Feature.LoggingEnabled {
		loggingScheduler := controller.NewScheduler(
			controller.CreateSynchronizationLoggingController(
				databaseRepository,
				logging.CreateLoggingRepository(logging.GetLoggingApiClient(properties.Logging)),
				properties.Logging),
			properties.SynchronizationController)

		go loggingScheduler.Run()
	}

	httpServer := server.NewServer(properties.HttpServer, false)
	managementServer := server.NewServer(properties.ManagementServer, true)

	handler := handlers.CreateHandler()

	generated.RegisterHandlers(httpServer, handler)
	errors := server.RunServers(httpServer, managementServer)

	select {
	case err := <-errors:
		panic(err)
	}
}

func getK8SClient() *kubernetes.Clientset {
	config, err := rest.InClusterConfig()
	if err != nil {
		dir, err := os.UserHomeDir()
		if err != nil {
			panic(fmt.Sprintf("cannot determine user-home dir: %s", err))
		}

		config, err = clientcmd.BuildConfigFromFlags("", dir+"/kubeconfig.json")
		if err != nil {
			panic(fmt.Sprintf("Unable to get our client configuration: %s", err))
		}
	}

	k8sClient := kubernetes.NewForConfigOrDie(config)
	return k8sClient
}
